home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / pc / files / t_unix / j109lxa4.tar / convers.c < prev    next >
C/C++ Source or Header  |  1994-06-04  |  45KB  |  1,792 lines

  1. /* convers server - based on conversd written by DK5SG
  2.  * ported to WNOS by DB3FL - 9109xx/9110xx
  3.  * ported to NOS by PE1NMB - 920120
  4.  * Mods by PA0GRI
  5.  * Cleanup, and additional mods by WG7J
  6.  */
  7.  
  8. #include <stdio.h>
  9. #include <string.h>
  10. #include <time.h>
  11. #include <ctype.h>
  12. #ifdef    UNIX
  13. #include <sys/types.h>
  14. #include <sys/stat.h>
  15. #endif
  16. #ifdef MSDOS
  17. #include <io.h>
  18. #endif
  19. #include "global.h"
  20. #include "config.h"
  21. #include "mailbox.h"
  22. #include "netuser.h"
  23. #include "pktdrvr.h"
  24. #include "timer.h"
  25. #include "cmdparse.h"
  26. #include "usock.h"
  27. #include "socket.h"
  28. #include "session.h"
  29. #include "files.h"
  30. #include "commands.h"
  31.  
  32. #ifdef CONVERS
  33.  
  34. #define    LINK    1
  35. #define space
  36.  
  37.  
  38.  
  39. int Sconv = -1;
  40. char Chostname[CNAMELEN+1];
  41. void conv_incom __ARGS((int s,void *t,void *p));
  42.  
  43. #ifdef space
  44. static char cnumber[] = "*** Channel numbers must be in the range 0..%d.\n";
  45. #else
  46. static char cnumber[] = "* range 0..%d.\n";
  47. #endif
  48.  
  49. #define MAXCHANNEL     32767
  50. #define LINELEN     256
  51. #define MAX_WAITTIME    (60*60*3)
  52. #define NAMELEN 10
  53.  
  54. struct convection {
  55.     int  type;            /* Connection type */
  56. #define CT_UNKNOWN      0
  57. #define CT_USER         1
  58. #define CT_HOST         2
  59. #define CT_CLOSED       3
  60.     char  name[NAMELEN+1];         /* Name of user or host */
  61.     char  host[NAMELEN+1];         /* Name of host where user is logged on */
  62.     struct convection *via;        /* Pointer to neighbor host */
  63.     char *data;                 /* room for some personal data */
  64.     int channel;            /* Channel number */
  65.     int32 time;            /* Connect time */
  66.     int locked;            /* Set if mesg already sent */
  67.     int fd;                /* Socket descriptor */
  68.     int flags;          /* User flags */
  69. #define CLOSE_SOCK  1
  70. #define USE_SOUND   2
  71.     char ibuf[LINELEN];        /* Input buffer */
  72.     int  received;            /* Number of bytes received */
  73.     int  xmitted;            /* Number of bytes transmitted */
  74.     struct convection *next;    /* Linked list pointer */
  75. };
  76.  
  77. #define CM_UNKNOWN    (1 << CT_UNKNOWN)
  78. #define CM_USER        (1 << CT_USER)
  79. #define CM_HOST        (1 << CT_HOST)
  80. #define CM_CLOSED    (1 << CT_CLOSED)
  81.  
  82. #define NULLCONNECTION    ((struct convection *) 0)
  83.  
  84. /* put this after declaration of "struct convection" or gcc has a conniption */
  85. #ifdef LINK
  86. struct proc *Linker;
  87. static void connect_permlinks __ARGS((int a,void *b,void *c));
  88. static void update_permlinks __ARGS((char *name,struct convection *cp));
  89. static void check_buffer_overload __ARGS((void));
  90. static int Allow_host __ARGS((int s));
  91. #endif
  92.  
  93. static struct convection *convections;
  94.  
  95. struct permlink {
  96.     char name[NAMELEN+1];   /* Name of link */
  97.     int32 addr;             /* address to link to */
  98.     struct convection *convection;    /* Pointer to associated connection */
  99.     int32 statetime;        /* Time of last (dis)connect */
  100.     int  tries;            /* Number of connect tries */
  101.     int32 waittime;            /* Time between connect tries */
  102.     int32 retrytime;        /* Time of next connect try */
  103.     int fd;                /* socket descriptor */
  104.     struct permlink *next;        /* Linked list pointer */
  105. };
  106. #define NULLPERMLINK ((struct permlink *) 0)
  107.  
  108. struct filter_link {
  109.     struct filter_link *next;
  110.     int32 addr;
  111. };
  112. #define NULLFL ((struct filter_link *) 0)
  113.  
  114. static struct filter_link *Filterlinks;
  115. static int FilterMode;
  116. static struct permlink *permlinks;
  117. extern char Ccall[AXALEN];
  118.  
  119. static int docfilter __ARGS((int argc,char *argv[],void *p));
  120. static int dochostname __ARGS((int argc,char *argv[],void *p));
  121. static int dociface __ARGS((int argc,char *argv[],void *p));
  122. static int doconfcall __ARGS((int argc,char *argv[],void *p));
  123. static int doclink __ARGS((int argc,char *argv[],void *p));
  124. static int doct4 __ARGS((int argc,char *argv[],void *p));
  125. static int docmaxwait __ARGS((int argc,char *argv[],void *p));
  126. static int docmaxq __ARGS((int argc,char *argv[],void *p));
  127. static void set_personal __ARGS((struct convection *cp));
  128.  
  129. static struct cmds DFAR Ccmds[] = {
  130.     "filter",   docfilter,  0, 0, NULLCHAR,
  131.     "hostname", dochostname,0, 0, NULLCHAR,
  132.     "interface",dociface,   0, 0, NULLCHAR,
  133.     "maxwait",  docmaxwait, 0, 0, NULLCHAR,
  134.     "maxq",     docmaxq,    0, 0, NULLCHAR,
  135. #ifdef AX25
  136.     "mycall",   doconfcall, 0, 0, NULLCHAR,
  137. #endif
  138. #ifdef LINK
  139.     "link",     doclink,    0, 0, NULLCHAR,
  140. #endif
  141. #ifdef AX25
  142.     "t4",       doct4,      0, 0, NULLCHAR,
  143. #endif
  144.     NULLCHAR,
  145. };
  146.  
  147. /* Multiplexer for top-level convers command */
  148. int
  149. #ifdef PROTOTYPES
  150. doconvers(int argc,char **argv,void *p)
  151. #else
  152. doconvers(argc,argv,p)
  153. int argc;
  154. char *argv[];
  155. void *p;
  156. #endif
  157. {
  158.     return subcmd(Ccmds,argc,argv,p);
  159. }
  160.  
  161. #ifdef AX25
  162. /* Display or change our AX.25 conference call */
  163. static int
  164. doconfcall(argc,argv,p)
  165. int argc;
  166. char *argv[];
  167. void *p;
  168. {
  169.     char tmp[AXBUF];
  170.  
  171.     if(argc < 2){
  172.         tprintf("%s\n",pax25(tmp,Ccall));
  173.         return 0;
  174.     }
  175.     if(setcall(Ccall,argv[1]) == -1)
  176.         return -1;
  177.     return 0;
  178. }
  179.  
  180. int32 CT4init = 7200;   /* 2 hours default */
  181.  
  182. /* Set link redundancy timer */
  183. static int
  184. doct4(argc,argv,p)
  185. int argc;
  186. char *argv[];
  187. void *p;
  188. {
  189.     return setlong(&CT4init,"Conf. redundancy timer (sec)",argc,argv);
  190. }
  191. #endif /* AX25 */
  192.  
  193. int32 CMaxwait = MAX_WAITTIME;
  194.  
  195. /* Set maxwait time for timed out links */
  196. static int
  197. docmaxwait(argc,argv,p)
  198. int argc;
  199. char *argv[];
  200. void *p;
  201. {
  202.     return setlong(&CMaxwait,"Re-link max wait (sec)",argc,argv);
  203. }
  204.  
  205. int32 CMaxQ = 5*1024L;
  206.  
  207. /* Set maxwait time for timed out links */
  208. static int
  209. docmaxq(argc,argv,p)
  210. int argc;
  211. char *argv[];
  212. void *p;
  213. {
  214.     return setlong(&CMaxQ,"Max. Queue (bytes)",argc,argv);
  215. }
  216.  
  217. static int
  218. dochostname(argc,argv,p)
  219. int argc;
  220. char *argv[];
  221. void *p;
  222. {
  223.     if(argc == 1)
  224.         tprintf("%s\n",Chostname);
  225.     else {
  226.         strncpy(Chostname,argv[1],NAMELEN);
  227.         Chostname[CNAMELEN] = '\0';
  228.     }
  229.     return 0;
  230. }
  231.  
  232. static int
  233. docfilter(argc,argv,p)
  234. int argc;
  235. char *argv[];
  236. void *p;
  237. {
  238.     int32 addr;
  239.     struct filter_link *fl;
  240.  
  241.     if(argc == 1) {
  242.         if(Filterlinks) {
  243.             tprintf("Mode is: %s\n", FilterMode ? "Accept" : "Refuse");
  244.             for(fl=Filterlinks;fl;fl=fl->next)
  245.                 tprintf("%s\n",inet_ntoa(fl->addr));
  246.         }
  247.         return 0;
  248.     }
  249.     if(!stricmp(argv[1],"mode")) {
  250.         if(argc == 2)
  251.             tprintf("Mode is: %s\n", FilterMode ? "Accept" : "Refuse");
  252.         else {
  253.             if(*argv[2] == 'a' || *argv[2] == 'A')
  254.                 FilterMode = 1;
  255.             else
  256.                 FilterMode = 0;
  257.         }
  258.         return 0;
  259.     }
  260.     if((addr = resolve(argv[1])) == 0) {
  261.         tprintf(Badhost,argv[1]);
  262.         return 1;
  263.     }
  264.     /* check to see if we already have this in the list */
  265.     for(fl=Filterlinks;fl;fl=fl->next)
  266.         if(fl->addr == addr)
  267.             return 0;       /* already have this one ! */
  268.  
  269.     /* Seems like a new one */
  270.     fl = (struct filter_link *)callocw(1,sizeof(struct filter_link));
  271.     fl->addr = addr;
  272.     fl->next = Filterlinks;
  273.     Filterlinks = fl;
  274.     return 0;
  275. }
  276.  
  277. #ifdef LINK
  278. static int
  279. doclink(argc,argv,p)
  280. int argc;
  281. char *argv[];
  282. void *p;
  283. {
  284.     int32 addr;
  285.     struct permlink *pl;
  286.  
  287.     if(argc == 1) {
  288.         for(pl=permlinks;pl;pl=pl->next)
  289.             tprintf("%10s: %s\n",pl->name,inet_ntoa(pl->addr));
  290.         return 0;
  291.     }
  292.     if((addr = resolve(argv[1])) == 0) {
  293.         tprintf(Badhost,argv[1]);
  294.         return 1;
  295.     }
  296.     /* check to see if we already have a link to such animal,
  297.      * this happens when we stop and restart the server - WG7J
  298.      */
  299.     for(pl=permlinks;pl;pl=pl->next)
  300.         if(pl->addr == addr)
  301.             return 1;       /* already have this one ! */
  302.  
  303.     /* Seems like a new link ! Go add it */
  304.     pl = (struct permlink *)callocw(1,sizeof(struct permlink ));
  305.     pl->addr = addr;
  306.     pl->next = permlinks;
  307.     permlinks = pl;
  308.     if(argc > 2) {
  309.         strncpy(pl->name,argv[2],NAMELEN);
  310.         update_permlinks(pl->name,NULLCONNECTION);
  311.     } else
  312.         strcpy(pl->name,"Unknown");
  313.     if(!Linker)
  314.         Linker = newproc("Clinker",1024,connect_permlinks,0,0,NULL,0);
  315.  
  316.     return 0;
  317. }
  318. #endif
  319.  
  320. static int
  321. dociface(argc,argv,p)
  322. int argc;
  323. char *argv[];
  324. void *p;
  325. {
  326.     return setflag(argc,argv[1],IS_CONV_IFACE,argv[2]);
  327. }
  328.  
  329. /* Stop convers server */
  330. int
  331. #ifdef PROTOTYPES
  332. conv0(int argc,char **argv,void *p)
  333. #else
  334. conv0(argc,argv,p)
  335. int argc;
  336. char *argv[];
  337. void *p;
  338. #endif
  339. {
  340.     close_s(Sconv);
  341.     Sconv = -1;
  342.     return 0;
  343. }
  344.  
  345. /* Start up convers server */
  346. int
  347. #ifdef PROTOTYPES
  348. conv1(int argc,char **argv,void *p)
  349. #else
  350. conv1(argc,argv,p)
  351. int argc;
  352. char *argv[];
  353. void *p;
  354. #endif
  355. {
  356.     struct sockaddr_in lsocket;
  357.     int s;
  358.  
  359.     if(Sconv != -1){
  360.         return 0;
  361.     }
  362.     psignal(Curproc,0);         /* Don't keep the parser waiting */
  363.     chname(Curproc,"Convers listener");
  364.  
  365.     lsocket.sin_family = AF_INET;
  366.     lsocket.sin_addr.s_addr = INADDR_ANY;
  367.     lsocket.sin_port = (argc < 2) ? IPPORT_CONVERS : atoi(argv[1]);
  368.  
  369.     Sconv = socket(AF_INET,SOCK_STREAM,0);
  370.     bind(Sconv,(char *)&lsocket,sizeof(lsocket));
  371.     listen(Sconv,1);
  372.     for(;;){
  373.         if((s = accept(Sconv,NULLCHAR,(int *)NULL)) == -1)
  374.             break;            /* Service is shutting down */
  375.         /* Low mem check now done in tcpin.c - WG7J */
  376.         /* Spawn a server */
  377.         if(newproc("conversd",2048,conv_incom,s,0,NULL,0) == NULLPROC)
  378.             close_s(s);
  379.     }
  380. #ifdef LINK
  381.     if(Linker)
  382.         killproc(Linker);
  383. #endif
  384.     return 0;
  385. }
  386.  
  387. static void
  388. #ifdef PROTOTYPES
  389. free_connection(register struct convection *cp)
  390. #else
  391. free_connection(cp)
  392. register struct convection *cp;
  393. #endif
  394. {
  395.     register struct permlink *p;
  396.  
  397.     for(p = permlinks; p; p = p->next)
  398.         if(p->convection == cp)
  399.             p->convection = NULLCONNECTION;
  400.     if(cp->flags & CLOSE_SOCK)
  401.         close_s(cp->fd);
  402.     free((char *) cp);
  403. }
  404.  
  405. static void
  406. #ifdef PROTOTYPES
  407. free_closed_connections(void)
  408. #else
  409. free_closed_connections()
  410. #endif
  411. {
  412.     register struct convection *cp,*p;
  413.     time_t currtime;
  414.  
  415.     currtime = time(&currtime);
  416.  
  417.     for(p = NULLCONNECTION,cp = convections; cp; )
  418.         if(cp->type == CT_CLOSED ||
  419.             (cp->type == CT_UNKNOWN && cp->time + 300 < currtime)){
  420.         if(p) {
  421.             p->next = cp->next;
  422.             free_connection(cp);
  423.             cp = p->next;
  424.         } else {
  425.             convections = cp->next;
  426.             free_connection(cp);
  427.             cp = convections;
  428.         }
  429.     } else {
  430.         p = cp;
  431.         cp = cp->next;
  432.     }
  433. }
  434.  
  435. static void
  436. update_permlinks(name,cp)
  437. char *name;
  438. struct convection *cp;
  439. {
  440.     register struct permlink *p;
  441.     time_t currtime;
  442.  
  443.     for(p = permlinks; p; p = p->next)
  444.         if(!strcmp(p->name,name)) {
  445.             currtime = time(&currtime);
  446.             p->convection = cp;
  447.             p->statetime = currtime;
  448.             p->tries = 0;
  449.             p->waittime = 60;
  450.             p->retrytime = currtime + p->waittime;
  451.         }
  452. }
  453.  
  454. static struct convection *
  455. #ifdef PROTOTYPES
  456. alloc_connection(int fd)
  457. #else
  458. alloc_connection(fd)
  459. int  fd;
  460. #endif
  461. {
  462.     register struct convection *cp;
  463.     time_t currtime;
  464.  
  465.     currtime = time(NULL);
  466.  
  467.     cp = (struct convection *)callocw(1,sizeof(struct convection ));
  468.     cp->fd = fd;
  469.     cp->flags = CLOSE_SOCK+USE_SOUND;       /* close on exit, by default */
  470.     cp->time = currtime;
  471.     cp->next = convections;
  472.     convections = cp;
  473.     return cp;
  474. }
  475.  
  476. #ifdef LINK
  477. /* check the host links for backlogged data.
  478.  * If larger then set threshold, kill the link.
  479.  * WG7J, 930208
  480.  */
  481. void check_buffer_overload(void) {
  482.     struct convection *p;
  483.     struct usock *up;
  484.  
  485.     /* check the size of the outstanding data buffers */
  486.     for(p = convections; p; p = p->next)
  487.         if( (p->type == CT_HOST) &&
  488.             ((up = itop(p->fd)) != NULLUSOCK) &&
  489.             (up->cb.tcb->sndcnt > CMaxQ) )
  490.                 reset_tcp(up->cb.tcb);
  491. }
  492.  
  493. void
  494. connect_permlinks(a,b,c)
  495. int a;
  496. void *b;
  497. void *c;
  498. {
  499.     int s;
  500.     register struct permlink *p;
  501.     struct sockaddr_in cport;
  502.     time_t currtime;
  503.  
  504.     for(;;) {
  505.         pause(15000L);
  506.         for(p = permlinks; p; p = p->next) {
  507.             currtime = time(&currtime);
  508.             if(p->convection || p->retrytime > currtime)
  509.                 continue;
  510.             p->tries++;
  511.             p->waittime <<= 1;
  512.             if(p->waittime > CMaxwait)
  513.                 p->waittime = CMaxwait;
  514.             p->retrytime = p->waittime + currtime;
  515.             cport.sin_family = AF_INET;
  516.             cport.sin_port = IPPORT_CONVERS;
  517.             cport.sin_addr.s_addr = p->addr; /* we've resolved this earlier */
  518.             if((s = socket(AF_INET,SOCK_STREAM,0)) == -1)
  519.                 continue;
  520.             if(connect(s,(char *)&cport,SOCKSIZE) == -1) {
  521.                 shutdown(s,2);  /* to make sure it doesn't linger around */
  522.                 close_s(s);     /* WG7J - 9207228 */
  523.                 continue;
  524.             }
  525.             p->fd = s;
  526.             if(newproc("permlink",2048,conv_incom,s,0,NULL,0) == NULLPROC){
  527.                 shutdown(s,2);  /* blow it out of the water :-) */
  528.                 close_s(s);
  529.             }
  530.         }
  531.         check_buffer_overload();
  532.     }
  533. }
  534. #endif
  535.  
  536.  
  537. static void
  538. #ifdef PROTOTYPES
  539. clear_locks(void)
  540. #else
  541. clear_locks()
  542. #endif
  543. {
  544.     register struct convection *p;
  545.  
  546.     for(p = convections;p;p = p->next)
  547.         p->locked = 0;
  548. }
  549.  
  550. static void send_sounds(struct convection *p) {
  551.     if(p->flags & USE_SOUND)
  552.         p->xmitted += usputs(p->fd,"");
  553. }
  554.  
  555. static void
  556. #ifdef PROTOTYPES
  557. send_user_change_msg(char *name,char *host,int oldchannel,int newchannel)
  558. #else
  559. send_user_change_msg(name,host,oldchannel,newchannel)
  560. char  *name,*host;
  561. int  oldchannel,newchannel;
  562. #endif
  563. {
  564.     register struct convection *p;
  565.  
  566.     for(p = convections; p; p = p->next) {
  567.         if(p->type == CT_USER && !p->via && !p->locked) {
  568.             if(p->channel == oldchannel) {
  569.                 if(newchannel >= 0) {
  570.                     p->xmitted += usprintf(p->fd,
  571.                         "*** %s switched to channel %d.\n",
  572.                          name,newchannel);
  573.                 } else
  574.                     p->xmitted += usprintf(p->fd,
  575.                         "*** %s signed off.\n",name);
  576.                 p->locked = 1;
  577.             }
  578.             if(p->channel == newchannel) {
  579.                 send_sounds(p);
  580.                 p->xmitted += usprintf(p->fd,
  581.                         "*** %s signed on.\n",name);
  582.                 p->locked = 1;
  583.             }
  584.         }
  585.         if(p->type == CT_HOST && !p->locked) {
  586.             p->xmitted += usprintf(p->fd,
  587.                 "/\377\200USER %s %s %d %d %d\n",
  588.                 name,host,0,oldchannel,newchannel);
  589.             p->locked = 1;
  590.         }
  591.     }
  592.     return;
  593. }
  594.  
  595. #ifdef Oldcode
  596.  
  597. static char *
  598. formatline(prefix,text)
  599. char  *prefix,*text;
  600. {
  601.  
  602. #define PREFIXLEN 10
  603. #define CONVLINELEN   79
  604.  
  605.     register char  *f,*t,*x;
  606.     register int  l,lw;
  607.  
  608.     static char buf[2*LINELEN];
  609.  
  610.     for(f = prefix,t = buf; *f; *t++ = *f++) ;
  611.     l = (int)(t - buf);
  612.     f = text;
  613.  
  614.     for(;;) {
  615.         while(isspace(uchar(*f)))
  616.             f++;
  617.         if(!*f) {
  618.             *t++ = '\n';
  619.             *t = '\0';
  620.             return buf;
  621.         }
  622.         for(x = f; *x && !isspace(uchar(*x)); x++) ;
  623.         lw = (int)(x - f);
  624.         if(l > PREFIXLEN && l + 1 + lw > CONVLINELEN) {
  625.             *t++ = '\n';
  626.             l = 0;
  627.         }
  628.         do {
  629.             *t++ = ' ';
  630.             l++;
  631.         } while(l < PREFIXLEN);
  632.         while(lw--) {
  633.             *t++ = *f++;
  634.             l++;
  635.         }
  636.     }
  637. }
  638.  
  639. static void
  640. send_msg_to_user(fromname,toname,text)
  641. char  *fromname,*toname,*text;
  642. {
  643.     register struct convection *p;
  644.     char buffer[2*LINELEN];
  645.  
  646.     for(p = convections; p; p = p->next) {
  647.         if(p->type == CT_USER && !strcmp(p->name,toname))
  648.             if(p->via) {
  649.                 if(!p->via->locked) {
  650.                     p->via->xmitted += usprintf(p->via->fd,
  651.                     "/\377\200UMSG %s %s %s\n",fromname,toname,text);
  652.                     p->via->locked = 1;
  653.                 }
  654.             } else {
  655.                 if(!p->locked) {
  656.                     if(strcmp(fromname,"conversd")) {
  657.                         sprintf(buffer,"<*%s*>:",fromname);
  658.                         p->xmitted += usprintf(p->fd,"%s",formatline(buffer,text));
  659.                 } else {
  660.                     p->xmitted += usprintf(p->fd,"%s\n",text);
  661.                 }
  662.                 p->locked = 1;
  663.             }
  664.         }
  665.     }
  666.     return;
  667. }
  668.  
  669. static void
  670. send_msg_to_channel(fromname,channel,text)
  671. char  *fromname;
  672. int  channel;
  673. char  *text;
  674. {
  675.     char  buffer[3*LINELEN];
  676.     register struct convection *p;
  677.  
  678.     for(p = convections; p; p = p->next) {
  679.         if(p->type == CT_USER && p->channel == channel)
  680.             if(p->via) {
  681.                 if(!p->via->locked) {
  682.                     p->via->xmitted += usprintf(p->via->fd,
  683.                     "/\377\200CMSG %s %d %s\n",fromname,channel,text);
  684.                     p->via->locked = 1;
  685.                 }
  686.             } else {
  687.                 if(!p->locked) {
  688.                     sprintf(buffer,"<%s>:",fromname);
  689.                     p->xmitted += usprintf(p->fd,"%s",formatline(&buffer[0],text));
  690.                     p->locked = 1;
  691.                 }
  692.             }
  693.     }
  694. }
  695.  
  696. #else /* Oldcode */
  697.  
  698. /* Returns a formatted version of the given text.
  699.  * The prefix appears at the beginning of the text, and each
  700.  * line after the first will be indented to column PREFIXLEN.
  701.  * All whitespace (SPACE and TAB) will be replaced by a single
  702.  * SPACE character,
  703.  * Lines will be filled to be CONVLINELEN characters long, wrapping
  704.  * words as necessary.
  705.  *
  706.  * This uses an static internal  buffer rather than one passed by
  707.  * the caller.  This increases the static memory used by the program
  708.  * even if converse isn't active.  If we passed a buffer  allocated
  709.  * on the stack, the process's stack would have to be large enough.
  710.  */
  711. static char *
  712. #ifdef PROTOTYPES
  713. formatline(char *prefix, char *text)
  714. #else
  715. formatline(prefix, text)
  716. char  *prefix, *text;
  717. #endif
  718. {
  719.  
  720. #   define PREFIXLEN    10
  721. #   define CONVLINELEN  79
  722. #   define FMTBUFLEN    LINELEN
  723.  
  724.     static char          buf[FMTBUFLEN];
  725.     register char       *f, *t;
  726.     register int         l, lw;
  727.     register int         left = FMTBUFLEN-2;
  728.     /* Runs of characters in delims[] will be collapsed into a single
  729.        space by formatline().
  730.      */
  731.     char                *delims = " \t\n\r";
  732.  
  733. #   define BPUTC(c)     do{ if (left > 0) { left--; *t++ = (c); }} while(0)
  734.  
  735.     /* Copy prefix into buf; set l to length of prefix.
  736.      */
  737.     l = 0;
  738.     for (f = prefix, t = buf; *f; ) {
  739.         BPUTC (*f++);
  740.         l++;
  741.     }
  742.  
  743.     f = text;
  744.  
  745.     for (;;) {
  746.         /* Skip leading spaces */
  747.         while (isspace(uchar(*f)))
  748.             f++;
  749.  
  750.         /* Return if nothing more or no room left */
  751.         if (!*f || (left <= 0)) {
  752.             *t++ = '\n';        /* don't use BPUTC; do even if !left */
  753.             *t   = '\0';
  754.             return buf;
  755.         }
  756.  
  757.         /* Find length of next word (seq. of non-blanks) */
  758.         lw = strcspn (f, delims);
  759.  
  760.         /* If the word would extend past end of line, do newline */
  761.         if (l > PREFIXLEN && (l + 1 + lw) > CONVLINELEN) {
  762.             BPUTC ('\n');
  763.             l = 0;
  764.         }
  765.  
  766.         /* Put out a single space */
  767.         do {
  768.             BPUTC (' ');
  769.             l++;
  770.         } while(l < PREFIXLEN);
  771.  
  772.         /* Put out the word */
  773.         while(lw--) {
  774.             BPUTC (*f++);
  775.             l++;
  776.         }
  777.     }
  778. #   undef BPUTC
  779. }
  780.  
  781.  
  782. static void
  783. #ifdef PROTOTYPES
  784. send_msg_to_user(char *fromname,char *toname,char *text)
  785. #else
  786. send_msg_to_user(fromname,toname,text)
  787. char  *fromname,*toname,*text;
  788. #endif
  789. {
  790.     register struct convection *p;
  791.  
  792.     for (p = convections; p; p = p->next) {
  793.         if(p->type == CT_USER && !strcmp(p->name,toname))
  794.             if(p->via) {
  795.                 if(!p->via->locked) {
  796.                     p->via->xmitted += usprintf(p->via->fd,
  797.                                         "/\377\200UMSG %.10s %.10s %.220s\n",
  798.                                         fromname, toname, text);
  799.                     p->via->locked = 1;
  800.                 }
  801.             } else {
  802.                 if(!p->locked) {
  803.                     if(strcmp(fromname,"conversd")) {
  804.                         char prefix[NAMELEN+10];
  805.                         char *buf;
  806.  
  807.                         sprintf(prefix,"<*%.10s*>:",fromname);
  808.  
  809.                         buf = formatline (prefix,text);
  810.                         p->xmitted += strlen (buf);
  811.                         (void) usputs (p->fd, buf);
  812.                     } else {    /* not from conversd */
  813.                         p->xmitted += strlen (text);
  814.                         (void) usputs (p->fd, text);
  815.                     }   /* not from conversd */
  816.                     p->locked = 1;
  817.                 } /* if not locked */
  818.             }   /* not via */
  819.     } /* for */
  820. }
  821.  
  822. static void
  823. #ifdef PROTOTYPES
  824. send_msg_to_channel(char *fromname,int channel,char *text)
  825. #else
  826. send_msg_to_channel(fromname,channel,text)
  827. char  *fromname;
  828. int  channel;
  829. char  *text;
  830. #endif
  831. {
  832.     register struct convection *p;
  833.  
  834.     for (p = convections; p; p = p->next) {
  835.         if(p->type == CT_USER && p->channel == channel)
  836.             if(p->via) {
  837.                 if(!p->via->locked) {
  838.                     p->via->xmitted += usprintf(p->via->fd,
  839.                                         "/\377\200CMSG %.10s %d %.220s\n",
  840.                                         fromname, channel, text);
  841.                     p->via->locked = 1;
  842.                 }
  843.             } else {
  844.                 if(!p->locked) {
  845.                     char         prefix[NAMELEN+10];
  846.                     char        *buf;
  847.  
  848.                     sprintf(prefix,"<%.10s>:", fromname);
  849.  
  850.                     buf = formatline (prefix, text);
  851.                     p->xmitted += strlen (buf);
  852.                     (void) usputs (p->fd, buf);
  853.  
  854.                     p->locked = 1;
  855.                 } /* not locked */
  856.             } /* not via */
  857.     } /* for */
  858. }
  859.  
  860.  
  861. #endif /* Oldcode */
  862.  
  863.  
  864. extern char *Months[];        /* in smtpserv.c */
  865.  
  866. static char  *
  867. #ifdef PROTOTYPES
  868. timestring(long gmt)
  869. #else
  870. timestring(gmt)
  871. long  gmt;
  872. #endif
  873. {
  874.     static char  buffer[10];
  875.     struct tm *tm;
  876.     time_t currtime;
  877.  
  878.     time(&currtime);
  879.     tm = localtime(&gmt);
  880.     if(gmt + 24 * 60 * 60 > currtime)
  881.         sprintf(buffer," %2d:%02d",tm->tm_hour,tm->tm_min);
  882.     else
  883.         sprintf(buffer,"%-3.3s %2d",Months[tm->tm_mon],tm->tm_mday);
  884.     return buffer;
  885. }
  886.  
  887. #ifdef space
  888.     char invitetext[] = "\n*** Message from %s at%s ...\nPlease join convers channel %d.\n\n";
  889.     char mbinvitetext[] = "\n*** Message from %s at%s ...\nPlease type 'C' to join convers, then goto channel %d.\n\n";
  890.     char responsetext[] = "*** Invitation sent to %s @ %s";
  891. #else
  892.     char invitetext[] = "\n*** Msg frm %s at%s ...\nPse join ch. %d.\n\n";
  893.     char mbinvitetext[] = "\n*** Msg frm %s at%s ...\nPse hit 'C' for convers; goto ch. %d.\n\n";
  894.     char responsetext[] = "*** sent to %s @ %s";
  895. #endif
  896.     char cnvd[] = "conversd";
  897.  
  898. static void
  899. #ifdef PROTOTYPES
  900. send_invite_msg(char *fromname,char *toname,int channel)
  901. #else
  902. send_invite_msg(fromname,toname,channel)
  903. char  *fromname,*toname;
  904. int  channel;
  905. #endif
  906. {
  907.  
  908.     char buffer[LINELEN];
  909.     struct convection *p;
  910. #ifdef MAILBOX
  911.     struct mbx *m;
  912. #endif
  913.     time_t currtime;
  914.  
  915.     currtime = time(&currtime);
  916.  
  917. #ifdef MAILBOX
  918.     /* Check users in the mailbox that aren't active */
  919.     for(m=Mbox;m;m=m->next){
  920.         if(m->state == MBX_CMD && !strcmp(m->name,toname)) {
  921.             usprintf(m->user,mbinvitetext,fromname,timestring(currtime),channel);
  922.             usflush(m->user);
  923.             clear_locks();
  924.             sprintf(buffer,responsetext,toname,"BBS@");
  925.             strcat(buffer,Hostname);
  926.             send_msg_to_user(cnvd,fromname,buffer);
  927.             return;
  928.         }
  929.     }
  930. #endif
  931.  
  932.     /* check the current convers users */
  933.     for(p = convections; p; p = p->next) {
  934.         if(p->type == CT_USER && !strcmp(p->name,toname)) {
  935.             if(p->channel == channel) {
  936.                 clear_locks();
  937.                 sprintf(buffer,"*** User %s is already on this channel.\n",toname);
  938.                 send_msg_to_user(cnvd,fromname,buffer);
  939.                 return;
  940.             }
  941.             if(!p->via && !p->locked) {
  942.                 p->xmitted += usprintf(p->fd,invitetext,fromname, \
  943.                                         timestring(currtime),channel);
  944.                 clear_locks();
  945.                 sprintf(buffer,responsetext,toname,Chostname);
  946.                 send_msg_to_user(cnvd,fromname,buffer);
  947.                 return;
  948.             }
  949.             if(p->via && !p->via->locked) {
  950.                 p->via->xmitted += usprintf(p->via->fd,
  951.                         "/\377\200INVI %s %s %d\n",fromname,toname,channel);
  952.                 return;
  953.             }
  954.         }
  955.     }
  956.     /* Nothing found locally, invite user on all links */
  957.     for(p = convections; p; p = p->next) {
  958.         if(p->type == CT_HOST && !p->locked) {
  959.             p->xmitted += usprintf(p->fd,
  960.                         "/\377\200INVI %s %s %d\n",fromname,toname,channel);
  961.         }
  962.     }
  963.     return;
  964. }
  965.  
  966. static void
  967. #ifdef PROTOTYPES
  968. bye_command(struct convection *cp)
  969. #else
  970. bye_command(cp)
  971. struct convection *cp;
  972. #endif
  973. {
  974.     register struct convection *p;
  975.  
  976.     switch(cp->type) {
  977.     case CT_UNKNOWN:
  978.         cp->type = CT_CLOSED;
  979.         break;
  980.     case CT_USER:
  981.         cp->type = CT_CLOSED;
  982.         clear_locks();
  983.         send_user_change_msg(cp->name,cp->host,cp->channel,-1);
  984.         break;
  985.     case CT_HOST:
  986.         cp->type = CT_CLOSED;
  987.         update_permlinks(cp->name,NULLCONNECTION);
  988.         for(p = convections; p; p = p->next)
  989.             if(p->via == cp) {
  990.                 p->type = CT_CLOSED;
  991.                 clear_locks();
  992.                 send_user_change_msg(p->name,p->host,p->channel,-1);
  993.             }
  994.         break;
  995.     case CT_CLOSED:
  996.         break;
  997.     }
  998. }
  999.  
  1000. static void
  1001. #ifdef PROTOTYPES
  1002. channel_command(struct convection *cp)
  1003. #else
  1004. channel_command(cp)
  1005. struct convection *cp;
  1006. #endif
  1007. {
  1008.     char  s[7];
  1009.     int  newchannel;
  1010.  
  1011.     s[0] = '\0';
  1012.     sscanf(cp->ibuf,"%*s %6s",s);
  1013.     if(s[0] == '\0') {
  1014. #ifdef space
  1015.     cp->xmitted += usprintf(cp->fd,"*** You are on channel %d.\n",cp->channel);
  1016. #else
  1017.     cp->xmitted += usprintf(cp->fd,"* On channel %d.\n",cp->channel);
  1018. #endif
  1019.         return;
  1020.     }
  1021.     newchannel = atoi(s);
  1022.     if(newchannel < 0) {
  1023.         /*  || newchannel > MAXCHANNEL) { */
  1024.         cp->xmitted += usprintf(cp->fd,cnumber,MAXCHANNEL);
  1025.         return;
  1026.     }
  1027.     if(newchannel == cp->channel) {
  1028.         cp->xmitted += usprintf(cp->fd,
  1029.                             "*** Already on channel %d.\n",cp->channel);
  1030.         return;
  1031.     }
  1032.     send_user_change_msg(cp->name,cp->host,cp->channel,newchannel);
  1033.     cp->channel = newchannel;
  1034.     cp->xmitted += usprintf(cp->fd,"*** Now on channel %d.\n",cp->channel);
  1035.     return;
  1036. }
  1037.  
  1038. static void
  1039. #ifdef PROTOTYPES
  1040. help_command(struct convection *cp)
  1041. #else
  1042. help_command(cp)
  1043. struct convection *cp;
  1044. #endif
  1045. {
  1046. #ifdef space
  1047.     cp->xmitted += usprintf(cp->fd,"Commands may be abbreviated. Commands are:\n");
  1048.     cp->xmitted += usprintf(cp->fd,"/? or /HELP\t\tPrint help information\n");
  1049.     cp->xmitted += usprintf(cp->fd,"/BYE\t\t\tTerminate the convers session\n");
  1050.     cp->xmitted += usprintf(cp->fd,"/CHANNEL n\t\tSwitch to channel n\n");
  1051.     cp->xmitted += usprintf(cp->fd,"/EXIT\t\t\tTerminate the convers session\n");
  1052.     cp->xmitted += usprintf(cp->fd,"/INVITE user\t\tInvite user to join your channel\n");
  1053.     cp->xmitted += usprintf(cp->fd,"/LINKS [LONG]\t\tList all connections to other hosts\n");
  1054.     cp->xmitted += usprintf(cp->fd,"/MSG user text...\tSend a private message to user\n");
  1055.     cp->xmitted += usprintf(cp->fd,"/PERSONAL text\t\tSet or show some personal text\n");
  1056.     cp->xmitted += usprintf(cp->fd,"/QUIT\t\t\tTerminate the convers session\n");
  1057.     cp->xmitted += usprintf(cp->fd,"/SOUNDS y|n\t\tTurn bell on or off\n");
  1058.     cp->xmitted += usprintf(cp->fd,"/WHO [QUICK]\t\tList all users and their channel numbers\n");
  1059.     cp->xmitted += usprintf(cp->fd,"/WRITE user text...\tSend a private message to user\n***\n");
  1060. #else
  1061.     cp->xmitted += usprintf(cp->fd,"no help\n");
  1062. #endif
  1063.     return;
  1064. }
  1065.  
  1066. static void
  1067. #ifdef PROTOTYPES
  1068. invite_command(struct convection *cp)
  1069. #else
  1070. invite_command(cp)
  1071. struct convection *cp;
  1072. #endif
  1073. {
  1074.     char toname[NAMELEN+1];
  1075.     char *cp1;
  1076.  
  1077.     toname[0] = '\0';
  1078.     sscanf(cp->ibuf,"%*s %10s",toname);
  1079.     if((cp1=strchr(toname,'@')) != NULLCHAR)
  1080.         *cp1 = '\0';
  1081.     if(toname[0] != '\0')
  1082.         send_invite_msg(cp->name,toname,cp->channel);
  1083.     return;
  1084. }
  1085.  
  1086. int ShowConfLinks(int s, int full) {
  1087.     int num;
  1088.     struct convection *pc;
  1089.     struct permlink *pp;
  1090.     char  tmp[20];
  1091.  
  1092.     num = usprintf(s,"Host       State         Since%s\n",
  1093.                 (full) ? " NextTry Tries Receivd Xmitted" : "");
  1094.     for(pc = convections; pc; pc = pc->next)
  1095.         if(pc->type == CT_HOST)
  1096.             num += usprintf(s,
  1097.                 (full) ?
  1098.                 "%-10s Connected    %s            %7d %7d\n" :
  1099.                 "%-10s Connected    %s\n",
  1100.                 pc->name,
  1101.                 timestring(pc->time),
  1102.                 pc->received,
  1103.                 pc->xmitted);
  1104.  
  1105.     for(pp = permlinks; pp; pp = pp->next)
  1106.         if(!pp->convection || pp->convection->type != CT_HOST) {
  1107.             strcpy(tmp,timestring(pp->retrytime));
  1108.             num += usprintf(s,
  1109.                 (full) ?
  1110.                 "%-10s %-12s %s %s %5d\n" :
  1111.                 "%-10s %-12s %s\n",
  1112.                 pp->name,
  1113.                 pp->convection ? "Connecting" : "Disconnected",
  1114.                 timestring(pp->statetime),
  1115.                 tmp,
  1116.                 pp->tries);
  1117.         }
  1118.     num += usprintf(s,"***\n");
  1119.     return num;
  1120. }
  1121.  
  1122. static void
  1123. #ifdef PROTOTYPES
  1124. links_command(struct convection *cp)
  1125. #else
  1126. links_command(cp)
  1127. struct convection *cp;
  1128. #endif
  1129. {
  1130.     char full[3];
  1131.     int f = 0;
  1132.  
  1133.     full[0] = '\0';
  1134.     sscanf(cp->ibuf,"%*s %2s",full);
  1135.     if(*full == 'l' || *full == 'L')
  1136.         f = 1;
  1137.     cp->xmitted += ShowConfLinks(cp->fd,f);
  1138.     return;
  1139. }
  1140.  
  1141. static void
  1142. #ifdef PROTOTYPES
  1143. msg_command(struct convection *cp)
  1144. #else
  1145. msg_command(cp)
  1146. struct convection *cp;
  1147. #endif
  1148. {
  1149.  
  1150.     char dummy[LINELEN],toname[NAMELEN+1],*text;
  1151.     register struct convection *p;
  1152.  
  1153.     toname[0] = '\0';
  1154.     sscanf(cp->ibuf,"%s %10s",dummy,toname);
  1155.     text = &cp->ibuf[0];
  1156.     text += strlen(dummy) + strlen(toname) + 2;
  1157.  
  1158.     if(!*text)
  1159.         return;
  1160.     for(p = convections; p; p = p->next)
  1161.         if(p->type == CT_USER && !strcmp(p->name,toname))
  1162.             break;
  1163.     if(!p)
  1164.         cp->xmitted += usprintf(cp->fd,"*** No such user: %s.\n",toname);
  1165.     else
  1166.         send_msg_to_user(cp->name,toname,text);
  1167.     return;
  1168. }
  1169.  
  1170. /* Set some personal data, like name and qth - WG7J */
  1171. static void
  1172. #ifdef PROTOTYPES
  1173. personal_command(struct convection *cp)
  1174. #else
  1175. personal_command(cp)
  1176. struct convection *cp;
  1177. #endif
  1178. {
  1179.     struct convection *p;
  1180.     char *cp2;
  1181.  
  1182.     if((cp2 = strchr(cp->ibuf,' ')) != NULLCHAR) {
  1183.         cp2++;
  1184.         if(*cp2) {  /* there actually is an argument */
  1185.             if(cp->data)
  1186.                 free(cp->data);
  1187.             rip(cp->ibuf);      /* get rid of ending '\n' */
  1188.             cp->data = strdup(cp2);
  1189.             /* update all links too ! - WG7J */
  1190.             for(p=convections;p;p=p->next)
  1191.                 if(p->type == CT_HOST)
  1192.                     p->xmitted += usprintf(p->fd,"/\377\200UDAT %s %s %s\n",
  1193.                                         cp->name,cp->host,cp->data);
  1194.             return;
  1195.         }
  1196.     }
  1197.     cp->xmitted += usprintf(cp->fd,"*** data set to: %s\n", \
  1198.             cp->data ? cp->data : "" );
  1199.     return;
  1200. }
  1201.  
  1202. /* find the personal information for this user */
  1203. void set_personal(struct convection *cp) {
  1204.     FILE *fp;
  1205.     char *cp1;
  1206.  
  1207.     if((fp = fopen(Cinfo,"r")) == NULL)
  1208.         return;
  1209.     while(fgets(cp->ibuf,LINELEN,fp) != NULL) {
  1210.         cp1 = cp->ibuf;
  1211.         /* find end of name */
  1212.         while(*cp1 != ' ' && *cp1 != '\t' && *cp1 != '\0')
  1213.             cp1++;
  1214.         if(!*cp1)
  1215.             continue;
  1216.         *cp1 = '\0';
  1217.         if(stricmp(cp->name,cp->ibuf))
  1218.             continue;
  1219.         /* Found personal data ! */
  1220.         *cp1 = ' ';
  1221.         fclose(fp);
  1222.         personal_command(cp);
  1223.         return;
  1224.     }
  1225.     fclose(fp);
  1226. }
  1227.  
  1228. /* protected by ftpusers file - WG7J */
  1229. static void
  1230. #ifdef PROTOTYPES
  1231. name_command(struct convection *cp)
  1232. #else
  1233. name_command(cp)
  1234. struct convection *cp;
  1235. #endif
  1236. {
  1237.     int  newchannel;
  1238.     char dummy[7];
  1239.     char *path;
  1240.     int pwdignore;
  1241.     long privs;
  1242.  
  1243.     cp->name[0] = '\0';
  1244.     dummy[0] = '\0';
  1245.     sscanf(cp->ibuf,"%*s %10s %6s",cp->name,dummy);
  1246.     newchannel = atoi(dummy);
  1247.     if(cp->name[0] == '\0')
  1248.         return;
  1249.     /* now check with ftpusers file - WG7J */
  1250.     if((path = mallocw(MBXLINE)) == NULLCHAR)
  1251.         return;
  1252.     pwdignore = 1;
  1253.     privs = userlogin(cp->name,NULLCHAR,&path,MBXLINE,&pwdignore);
  1254.     free(path);
  1255.     if(privs & NO_CONVERS)
  1256.         return;
  1257.     strlwr(cp->name);
  1258.     strcpy(cp->host,Chostname);
  1259.     cp->type = CT_USER;
  1260.     cp->xmitted += usprintf(cp->fd,
  1261.         "Conference @ %s  Type /HELP for help.\n",Chostname);
  1262.     if(newchannel < 0) {
  1263.         /* || newchannel > MAXCHANNEL) { */
  1264.         cp->xmitted += usprintf(cp->fd,cnumber,MAXCHANNEL);
  1265.     } else
  1266.         cp->channel = newchannel;
  1267.     send_user_change_msg(cp->name,cp->host,-1,cp->channel);
  1268.     set_personal(cp);
  1269.     return;
  1270. }
  1271.  
  1272. /* Set or show the status of the 'sound' flag - WG7J */
  1273. static void
  1274. #ifdef PROTOTYPES
  1275. sounds_command(struct convection *cp)
  1276. #else
  1277. sounds_command(cp)
  1278. struct convection *cp;
  1279. #endif
  1280. {
  1281.     char *cp2;
  1282.  
  1283.     if((cp2 = strchr(cp->ibuf,' ')) != NULLCHAR) {
  1284.         cp2++;
  1285.         if(*cp2) {   /* There is an argument */
  1286.             if(*cp2 == 'n' || *cp2 == 'N') {   /* Turn it off */
  1287.                 cp->flags &= ~USE_SOUND;
  1288.             } else
  1289.                 cp->flags |= USE_SOUND;
  1290.             return;
  1291.         }
  1292.     }
  1293.     if(cp->flags & USE_SOUND)
  1294.         usputs(cp->fd,"*** Sounds on\n");
  1295.     else
  1296.         usputs(cp->fd,"*** Sounds off\n");
  1297.     return;
  1298. }
  1299.  
  1300. /* Print a user display, return the number of characters sent */
  1301. int ShowConfUsers(int s,int quick) {
  1302.     int num,channel;
  1303.     struct convection *p;
  1304.     char buffer[LINELEN];
  1305. #ifdef MAILBOX
  1306.     struct mbx *m;
  1307. #endif
  1308.  
  1309.     if(quick) {
  1310.         num = usprintf(s,"Channel Users\n");
  1311.         clear_locks();
  1312.         do {
  1313.             channel = -1;
  1314.             for(p = convections; p; p = p->next) {
  1315.                 if(p->type == CT_USER &&
  1316.                   !p->locked &&
  1317.                   (channel < 0 || channel == p->channel)) {
  1318.                     if(channel < 0) {
  1319.                         channel = p->channel;
  1320.                         sprintf(buffer,"%7d",channel);
  1321.                     }
  1322.                     strcat(buffer," ");
  1323.                     strcat(buffer,p->name);
  1324.                     p->locked = 1;
  1325.                 }
  1326.             }
  1327.             if(channel >= 0) {
  1328.                 num += usprintf(s,"%s\n",buffer);
  1329.             }
  1330.         } while(channel >= 0);
  1331.     } else {
  1332.         num = usprintf(s,"User       Host       Via        Channel   Time Personal\n");
  1333.         for(p = convections; p; p = p->next) {
  1334.             if(p->type == CT_USER) {
  1335.                 num += usprintf(s,"%-10s %-10s %-10s %7d %s %s\n",
  1336.                     p->name,
  1337.                     p->host,
  1338.                     p->via ? p->via->name : "",
  1339.                     p->channel,
  1340.                     timestring(p->time),
  1341.                     p->data ? p->data : "" );
  1342.             }
  1343.         }
  1344.     }
  1345. #ifdef MAILBOX
  1346.     for(m=Mbox;m;m=m->next) {
  1347.         if(m->state == MBX_CMD) {
  1348.         if(quick)
  1349.             num += usprintf(s," BBS %s\n",m->name);
  1350.         else
  1351.             num += usprintf(s,"%-10s BBS@%s\n",m->name,Hostname);
  1352.         }
  1353.     }
  1354. #endif
  1355.     num += usprintf(s,"***\n");
  1356.     return num;
  1357. }
  1358.  
  1359. static void
  1360. #ifdef PROTOTYPES
  1361. who_command(struct convection *cp)
  1362. #else
  1363. who_command(cp)
  1364. struct convection *cp;
  1365. #endif
  1366. {
  1367.     char buffer[LINELEN];
  1368.     int quick = 0;
  1369.  
  1370.     buffer[0] = '\0';
  1371.     sscanf(cp->ibuf,"%*s %2s",buffer);
  1372.     switch(tolower(buffer[0])) {
  1373.     case 'q':
  1374.         quick = 1;
  1375.         break;
  1376.     }
  1377.     cp->xmitted += ShowConfUsers(cp->fd,quick);
  1378.     return;
  1379. }
  1380.  
  1381. static void
  1382. #ifdef PROTOTYPES
  1383. h_cmsg_command(struct convection *cp)
  1384. #else
  1385. h_cmsg_command(cp)
  1386. struct convection *cp;
  1387. #endif
  1388. {
  1389.     char *text;
  1390.     int  channel;
  1391.     char name[LINELEN],dummy[40];
  1392.  
  1393.     sscanf(cp->ibuf,"%s %10s %d",dummy,name,&channel);
  1394.     text = &cp->ibuf[0];
  1395.     text += strlen(dummy) + strlen(name) + 2;
  1396.     while(isspace(*text) == 0)
  1397.         text++;
  1398.     text++;
  1399.     if(isprint(*text) != 0)
  1400.         send_msg_to_channel(name,channel,text);
  1401.     return;
  1402. }
  1403.  
  1404. /* Return 1 if the host is to be allowed, or 0 if refused - WG7J */
  1405. int Allow_host(int s) {
  1406.     struct filter_link *fl;
  1407.     struct sockaddr_in fsocket;
  1408.     int i = sizeof(struct sockaddr_in);
  1409.  
  1410.     if(Filterlinks) {    /* Check for this ip address */
  1411.         getpeername(s,(char *)&fsocket,&i);
  1412.         for(fl=Filterlinks;fl;fl=fl->next)
  1413.             if(fl->addr == fsocket.sin_addr.s_addr)
  1414.                 return FilterMode;
  1415.         /* Not found ! */
  1416.         return !FilterMode;
  1417.     }
  1418.     return 1;
  1419. }
  1420.  
  1421. static void
  1422. #ifdef PROTOTYPES
  1423. h_host_command(struct convection *cp)
  1424. #else
  1425. h_host_command(cp)
  1426. struct convection *cp;
  1427. #endif
  1428. {
  1429.  
  1430.     char name[NAMELEN+1];
  1431.     struct convection *p;
  1432.     struct permlink *pp;
  1433.  
  1434.     if(!Allow_host(cp->fd)) {
  1435.         bye_command(cp);
  1436.         return;
  1437.     }
  1438.     name[0] = '\0';
  1439.     sscanf(cp->ibuf,"%*s %10s",name);
  1440.     if(name[0] == '\0') {
  1441.         bye_command(cp);
  1442.         return;
  1443.     }
  1444.     for(p = convections; p; p = p->next)
  1445.         if(!strcmp(p->name,name)) {
  1446.             bye_command(p);
  1447.             return;
  1448.         }
  1449.     for(pp = permlinks; pp; pp = pp->next)
  1450.         if(!strcmp(pp->name,name) && pp->convection && pp->convection != cp) {
  1451.             bye_command((strcmp(Chostname,name) < 0) ? pp->convection : cp);
  1452.             return;
  1453.         }
  1454. /*
  1455.     if(cp->type != CT_UNKNOWN)
  1456.         return;
  1457.  */
  1458.     cp->type = CT_HOST;
  1459.     strcpy(cp->name,name);        /* already allocated */
  1460.     update_permlinks(name,cp);
  1461.     cp->xmitted += usprintf(cp->fd,"/\377\200HOST %s\n",Chostname);
  1462.     for(p = convections; p; p = p->next)
  1463.         if(p->type == CT_USER) {
  1464.             cp->xmitted += usprintf(cp->fd,
  1465.                 "/\377\200USER %s %s %d %d %d\n",
  1466.                 p->name,p->host,0,-1,p->channel);
  1467.             if(p->data)
  1468.                 cp->xmitted += usprintf(cp->fd,
  1469.                         "/\377\200UDAT %s %s %s\n",
  1470.                         p->name,p->host,p->data);
  1471.         }
  1472.     return;
  1473. }
  1474.  
  1475. static void
  1476. #ifdef PROTOTYPES
  1477. h_invi_command(struct convection *cp)
  1478. #else
  1479. h_invi_command(cp)
  1480. struct convection *cp;
  1481. #endif
  1482. {
  1483.     char fromname[NAMELEN+1],toname[NAMELEN+1];
  1484.     int  channel;
  1485.  
  1486.     sscanf(cp->ibuf,"%*s %10s %10s %d",fromname,toname,&channel);
  1487.     send_invite_msg(fromname,toname,channel);
  1488.     return;
  1489. }
  1490.  
  1491. static void
  1492. #ifdef PROTOTYPES
  1493. h_loop_command(struct convection *cp)
  1494. #else
  1495. h_loop_command(cp)
  1496. struct convection *cp;
  1497. #endif
  1498. {
  1499.   char host[NAMELEN+1];
  1500.  
  1501.   sscanf(cp->ibuf,"%*s %10s",host);
  1502.   log(cp->fd, "conversd rx: LOOP %s",host);
  1503.   bye_command(cp);
  1504. }
  1505.  
  1506. /* Command to take user's personal data across a link - WG7J */
  1507. static void
  1508. #ifdef PROTOTYPES
  1509. h_udat_command(struct convection *cp)
  1510. #else
  1511. h_udat_command(cp)
  1512. struct convection *cp;
  1513. #endif
  1514. {
  1515.     char *name,*host,*data;
  1516.     struct convection *p;
  1517.  
  1518.     /* do a validity check first */
  1519.     if((name = strchr(cp->ibuf,' ')) == NULLCHAR)
  1520.         return;
  1521.     name++;
  1522.     if((host = strchr(name,' ')) == NULLCHAR)
  1523.         return;
  1524.     *host++ = '\0';
  1525.     if((data = strchr(host,' ')) == NULLCHAR)
  1526.         return;
  1527.     *data++ = '\0';
  1528.     rip(data);      /* rip the '\n' */
  1529.     if(strlen(data) == 0)
  1530.         return;
  1531.     /* everything seems fine, now find user ! */
  1532.     for(p=convections;p;p=p->next) {
  1533.         if(!strcmp(p->name,name) && !strcmp(p->host,host)) {
  1534.             if(p->data)
  1535.                 free(p->data);
  1536.             p->data = strdup(data);
  1537.         }
  1538.         /* update over other links  Apr 12/93 VE3DTE */
  1539.         if(p->type == CT_HOST && !p->locked)
  1540.                p->xmitted += usprintf(p->fd, "/\377\200UDAT %s %s %s\n",
  1541.                                 name,host,data);
  1542.     }
  1543. }
  1544.  
  1545. static void
  1546. #ifdef PROTOTYPES
  1547. h_umsg_command(struct convection *cp)
  1548. #else
  1549. h_umsg_command(cp)
  1550. struct convection *cp;
  1551. #endif
  1552. {
  1553.     char dummy[NAMELEN+1],fromname[NAMELEN+1],toname[NAMELEN+1],*text;
  1554.  
  1555.     sscanf(cp->ibuf,"%s %10s %10s",dummy,fromname,toname);
  1556.     text = &cp->ibuf[0];
  1557.     text += strlen(dummy) + strlen(fromname) + strlen(toname) + 3;
  1558.     if(*text)
  1559.     send_msg_to_user(fromname,toname,text);
  1560.     return;
  1561. }
  1562.  
  1563. static void
  1564. #ifdef PROTOTYPES
  1565. h_user_command(struct convection *cp)
  1566. #else
  1567. h_user_command(cp)
  1568. struct convection *cp;
  1569. #endif
  1570. {
  1571.     char host[NAMELEN+1],name[NAMELEN+1];
  1572.     int  newchannel,oldchannel;
  1573.     register struct convection *p;
  1574.     time_t currtime;
  1575.  
  1576.     currtime = time(&currtime);
  1577.  
  1578.     sscanf(cp->ibuf,"%*s %10s %10s %*s %d %d",name,host,&oldchannel,&newchannel);
  1579.  
  1580.     for(p = convections; p; p = p->next)
  1581.         if(p->type == CT_USER) {
  1582.             /* new 920705 dl9sau */
  1583.             /* If Neighbour2 registers a user on HostX, while someone has already
  1584.              * been registered for HostX via Neighbour1, then we definitely have
  1585.              * a loop !  We send a loop detect message and then close the link:
  1586.              * /..LOOP <Chostname> <myneighbour> <host>
  1587.              *
  1588.              * The LOOP PREVENTION CODE detects ONLY a loop if it starts at this
  1589.              * host. That's, why I suggest this code to be implemented in every
  1590.              * conversd implementation.
  1591.              */
  1592.             if (oldchannel < 0 && p->via != cp && !stricmp(p->host, host)) {
  1593.                 usprintf(cp->fd,"/\377\200LOOP %s %s %s\n", \
  1594.                     Chostname, host,p->via ? p->via->name : Chostname);
  1595.                 log(cp->fd, "conversd sent: LOOP %s",host);
  1596.                 bye_command(cp);
  1597.                 return;
  1598.             }
  1599.             if(p->channel == oldchannel && p->via == cp && \
  1600.                 !strcmp(p->name,name) && !strcmp(p->host,host))
  1601.             break;
  1602.         }
  1603.     if(!p) {
  1604.         p = (struct convection *)callocw(1,sizeof(struct convection ));
  1605.         p->type = CT_USER;
  1606.         strcpy(p->name,name);
  1607.         strcpy(p->host,host);
  1608.         p->via = cp;
  1609.         p->channel = oldchannel;
  1610.         p->time = currtime;
  1611.         p->next = convections;
  1612.         convections = p;
  1613.     }
  1614.     if((p->channel = newchannel) < 0) {
  1615.         p->type = CT_CLOSED;
  1616.         free_closed_connections();  /*  VE3DTE Apr 5/93 */
  1617.     }
  1618.     send_user_change_msg(name,host,oldchannel,newchannel);
  1619.     return;
  1620. }
  1621.  
  1622. struct cmdtable {
  1623.     char  *name;
  1624.     void (*fnc) __FARGS((struct convection *));
  1625.     int  states;
  1626. };
  1627. struct cmdtable DFAR cmdtable[] = {
  1628.         "?",        help_command,       CM_USER,
  1629.         "bye",      bye_command,        CM_USER,
  1630.         "channel",  channel_command,    CM_USER,
  1631.         "exit",     bye_command,        CM_USER,
  1632.         "help",     help_command,       CM_USER,
  1633.         "invite",   invite_command,     CM_USER,
  1634.         "links",    links_command,      CM_USER,
  1635.         "msg",      msg_command,        CM_USER,
  1636.         "name",     name_command,       CM_UNKNOWN,
  1637.         "personal", personal_command,   CM_USER,
  1638.         "quit",     bye_command,        CM_USER,
  1639.         "sounds",   sounds_command,     CM_USER,
  1640.         "who",      who_command,        CM_USER,
  1641.         "write",    msg_command,        CM_USER,
  1642.  
  1643.         "\377\200cmsg", h_cmsg_command,     CM_HOST,
  1644.         "\377\200host", h_host_command,     CM_UNKNOWN,
  1645.         "\377\200invi", h_invi_command,     CM_HOST,
  1646.         "\377\200loop", h_loop_command,     CM_HOST,
  1647.         "\377\200udat", h_udat_command,     CM_HOST,
  1648.         "\377\200umsg", h_umsg_command,     CM_HOST,
  1649.         "\377\200user", h_user_command,     CM_HOST,
  1650.         0,      0,          0,
  1651. };
  1652.  
  1653. static void
  1654. #ifdef PROTOTYPES
  1655. process_commands(struct convection *cp,struct mbx *m)
  1656. #else
  1657. process_commands(cp,m)
  1658. struct convection *cp;
  1659. struct mbx *m;
  1660. #endif
  1661. {
  1662.     char arg[LINELEN];
  1663.     int arglen,size;
  1664.     char *ccp;
  1665.     struct cmdtable *cmdp;
  1666.  
  1667.     for(;;) {
  1668. loop:
  1669.         if(cp->type == CT_CLOSED)
  1670.             break;
  1671. #ifdef MBXTDISC
  1672.         if(m) {
  1673.             /* Restart the inactivity timer - WG7J */
  1674.             start_timer(&m->tdisc);
  1675.         }
  1676. #endif
  1677.         usflush(cp->fd);
  1678.         memset(cp->ibuf,0,sizeof(cp->ibuf));
  1679.         if((size = recvline(cp->fd,cp->ibuf,sizeof(cp->ibuf)-1)) <= 0)
  1680.             break;
  1681.         cp->received += size;
  1682.         clear_locks();
  1683.         cp->locked = 1;
  1684.         if(*cp->ibuf == '/') {
  1685.             ccp = &cp->ibuf[1];
  1686.             arg[0] = '\0';
  1687.             sscanf(ccp,"%s",arg);
  1688.             arglen = strlen(arg);
  1689.             /* We are about to parse a command; most likely there
  1690.              * is alot of output; try to avoid fragmenting that
  1691.              * data by doing our own flushing ! - WG7J
  1692.              */
  1693.             setflush(cp->fd,-1);
  1694.             for(cmdp = cmdtable; cmdp->name; cmdp++) {
  1695.                 if(!strncmpi(cmdp->name,arg,(size_t)arglen)) {
  1696.                     if(cmdp->states & (1 << cp->type))
  1697.                         (*cmdp->fnc)(cp);
  1698.                     setflush(cp->fd,'\n');
  1699.                     goto loop;
  1700.                 }
  1701.             }
  1702.             if(cp->type == CT_USER)
  1703.                 cp->xmitted += usprintf(cp->fd,
  1704.                     "*** Unknown command '/%s'. Type /HELP for help.\n",arg);
  1705.             setflush(cp->fd,'\n');
  1706.             goto loop;
  1707.         }
  1708.         if((ccp = strpbrk(cp->ibuf,"\r\n")) != NULLCHAR)
  1709.             *ccp = '\0';
  1710.         if(isprint(cp->ibuf[0]) != 0 && cp->type == CT_USER)
  1711.             send_msg_to_channel(cp->name,cp->channel,cp->ibuf);
  1712.     }
  1713.     sockblock(cp->fd,SOCK_BLOCK);
  1714.     bye_command(cp);
  1715.     free_closed_connections();
  1716. }
  1717.  
  1718. /* Incoming convers session */
  1719. void
  1720. conv_incom(s,t,p)
  1721. int s;
  1722. void *t;
  1723. void *p;
  1724. {
  1725.     struct convection *cp;
  1726.     struct permlink *pl;
  1727.  
  1728.     sockowner(s,Curproc);    /* We own it now */
  1729.     sockmode(s,SOCK_BINARY);
  1730.     sockblock(s,SOCK_NOTXBLOCK);   /* prevent backlogs ! */
  1731.     cp = alloc_connection(s);
  1732.  
  1733.     for(pl = permlinks; pl; pl = pl->next)
  1734.         if(pl->fd == s) {
  1735.             pl->convection = cp;
  1736.             cp->xmitted += usprintf(s,"/\377\200HOST %s\n",Chostname);
  1737.         }
  1738.  
  1739.     if(pl == NULLPERMLINK) {
  1740.         usprintf(cp->fd,"\npse login with '/n <call>'\n\n");
  1741.     }
  1742.     process_commands(cp,NULLMBX);
  1743. }
  1744.  
  1745. #ifdef MAILBOX
  1746. #ifdef MBXTDISC
  1747. extern int32 Mbtdiscinit;
  1748. #endif
  1749.  
  1750. /* this is for Mailbox users */
  1751. void
  1752. mbox_converse(m)
  1753. struct mbx *m;
  1754. {
  1755.     struct convection *cp;
  1756.  
  1757.     sockblock(m->user,SOCK_NOTXBLOCK);  /* prevent backlogs ! */
  1758.     setflush(m->user,'\n');             /* automatic line flushing */
  1759.     cp = alloc_connection(m->user);
  1760.     strcpy(cp->name,m->name);
  1761.     strcpy(cp->host,Chostname);
  1762.     cp->type = CT_USER;
  1763.     cp->flags &= ~CLOSE_SOCK;     /* do not close socket on exit */
  1764.     cp->xmitted += usprintf(m->user,
  1765.             "Conference @ %s  Type /HELP for help.\n",Chostname);
  1766.     clear_locks();
  1767.     cp->locked = 1; /* send to everyone but ourself */
  1768.     send_user_change_msg(cp->name,cp->host,-1,0);
  1769.     set_personal(cp);
  1770.  
  1771. #ifdef MBXTDISC
  1772.     /* Set the timeout timer to the convers t4 value */
  1773.     stop_timer(&m->tdisc);
  1774.     set_timer(&m->tdisc,CT4init * 1000L);
  1775.     start_timer(&m->tdisc);
  1776. #endif
  1777.  
  1778.     process_commands(cp,m);
  1779.  
  1780.     setflush(m->user,-1);
  1781. #ifdef MBXTDISC
  1782.     /* Reset to the mailbox timeout value */
  1783.     stop_timer(&m->tdisc);
  1784.     set_timer(&m->tdisc,Mbtdiscinit * 1000L);
  1785.     start_timer(&m->tdisc);
  1786. #endif
  1787.  
  1788. }
  1789. #endif /* MAILBOX */
  1790.  
  1791. #endif /* CONVERS */
  1792.